#include <iostream>
#include <cstring>
#include <string>
#include <cerrno>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
#include <sys/wait.h>
#include <signal.h>
#include <pthread.h>
#include <memory>

static const uint16_t gport = 8080;

#define BACKLOG 8

class TcpServer
{
public:
    TcpServer(int port = gport)
        : _port(port),
          _isrunning(false)
    {
    }

    bool InitServer()
    {
        // 1. 创建tcp socket
        _listensockfd = ::socket(AF_INET, SOCK_STREAM, 0); // Tcp Socket
        if (_listensockfd < 0)
        {
            exit(1);
        }

        struct sockaddr_in local;
        memset(&local, 0, sizeof(local));
        local.sin_family = AF_INET;
        local.sin_port = htons(_port);
        local.sin_addr.s_addr = INADDR_ANY;

        // 2. bind
        int n = ::bind(_listensockfd, (sockaddr *)(&local), sizeof(local));
        if (n < 0)
        {
            exit(1);
        }

        // 3. cs tcp是面向连接的，就要求tcp随时随地等待被连接
        // tcp 需要将socket设置成为监听状态
        n = ::listen(_listensockfd, BACKLOG);
        if (n < 0)
        {
            exit(1);
        }

        //::signal(SIGCHLD, SIG_IGN);     // 子进程退出，OS会自动回收资源，不用再wait了
        return true;
    }

    void Start()
    {
        _isrunning = true;
        while (_isrunning)
        {
            // 不能直接读取数据
            // 1. 获取新连接
            struct sockaddr_in peer;
            socklen_t peerlen = sizeof(peer);
            // 我们要获取客户端的信息：数据(sockfd) + client socket信息（accept）
            int sockfd = ::accept(_listensockfd, (sockaddr *)(&peer), &peerlen);
            if (sockfd < 0)
            {
                continue;
            }

            char inbuffer[4096];
            // 长任务
            while (true)
            {
                ssize_t n = ::recv(sockfd, inbuffer, sizeof(inbuffer) - 1, 0);
                if (n > 0)
                {
                    inbuffer[n] = 0;
                    std::string echo_str = "server echo# ";
                    echo_str += inbuffer;

                    ::send(sockfd, echo_str.c_str(), echo_str.size(), 0);
                }
                else if (n == 0)
                {
                    // read 如果读取返回值是0，表示client退出
                    break;
                }
                else
                {
                    // 读取失败了
                    break;
                }
            }

            ::close(sockfd); // fd泄露问题
        }
    }

    void Stop()
    {
        _isrunning = false;
    }

    ~TcpServer()
    {
    }

private:
    int _listensockfd; // 监听socket
    uint16_t _port;
    bool _isrunning;
};

int main()
{
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>();

    tsvr->InitServer();
    tsvr->Start();

    return 0;
}